/**
 * 
 */
package org.vsg.security;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.Vector;

import org.jsecurity.authc.AuthenticationException;
import org.jsecurity.authc.AuthenticationInfo;
import org.jsecurity.authc.AuthenticationToken;
import org.jsecurity.authc.UnknownAccountException;
import org.jsecurity.authc.UsernamePasswordToken;
import org.jsecurity.authz.AuthorizationInfo;
import org.jsecurity.realm.AuthorizingRealm;
import org.jsecurity.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.vsg.security.model.domain.ResourceAssociation;
import org.vsg.security.model.domain.SysUser;
import org.vsg.security.model.persistence.SysUserDao;
import org.vsg.security.policy.HandlerPolicyException;
import org.vsg.security.policy.ResourceAssoHandlerPolicy;
import org.vsg.security.policy.RolesHandlerPolicy;
import org.vsg.security.policy.support.RoleHandlerPolicySupport;
import org.vsg.security.vo.SecRole;
import org.vsg.security.vo.SecRoleSort;

/**
 * @author Bill Vison
 *
 */
public class AccountAuthorizingRealm extends AuthorizingRealm implements RoleHandlerPolicySupport{

	private static final Logger logger = LoggerFactory.getLogger(AccountAuthorizingRealm.class);

	@Autowired
	private RolesHandlerPolicy roleHandlerPolicy;
	
	private ResourceAssoHandlerPolicy resoAssoHandlerPolicy;
	
	private SysUserDao sysUserDao;
	
	public AccountAuthorizingRealm() {
		// TODO Auto-generated constructor stub
		setName( AccountAuthorizingRealm.class.getName() );		
	}

	public SysUserDao getSysUserDao() {
		return sysUserDao;
	}

	public void setSysUserDao(SysUserDao sysUserDao) {
		this.sysUserDao = sysUserDao;
	}

	public RolesHandlerPolicy getRoleHandlerPolicy() {
		return roleHandlerPolicy;
	}

	public void setRoleHandlerPolicy(RolesHandlerPolicy roleHandlerPolicy) {
		this.roleHandlerPolicy = roleHandlerPolicy;
	}

	public ResourceAssoHandlerPolicy getResoAssoHandlerPolicy() {
		return resoAssoHandlerPolicy;
	}

	public void setResoAssoHandlerPolicy(
			ResourceAssoHandlerPolicy resoAssoHandlerPolicy) {
		this.resoAssoHandlerPolicy = resoAssoHandlerPolicy;
	}

	private AccountUser handlePolicy(SysUser user) {
		AccountUser account = null;
		
		try {
			
			Set<SecRole> grantRoles = roleHandlerPolicy.handlePolicy( user.getAssignedRoles() );
			
			// --- sort sec role collection ----
			Comparator compara = new SecRoleSort();
			List<SecRole> grantRolesList = new Vector<SecRole>(grantRoles);
			Collections.sort( grantRolesList , compara );

		
			// --- grantResAssociation ---
			Set<ResourceAssociation> grantAsso = resoAssoHandlerPolicy.handlePolicy( grantRolesList );
			
			account = new AccountUser(user , grantRoles , grantAsso);
		
		} catch (HandlerPolicyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		// --- add all permission ---
		
		
		return account;
	}

	/* (non-Javadoc)
	 * @see org.jsecurity.realm.AuthorizingRealm#doGetAuthorizationInfo(org.jsecurity.subject.PrincipalCollection)
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection prinColl) {
		// TODO Auto-generated method stub
		Collection allColl = prinColl.fromRealm( getName() );
		
		Iterator principalIter = allColl.iterator();
		
		Integer userId = null;
		if ( principalIter.hasNext() ) {
			userId = (Integer)principalIter.next();
		}
		
		SysUser user = sysUserDao.load(userId);
		return handlePolicy(user);
	}

	/* (non-Javadoc)
	 * @see org.jsecurity.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.jsecurity.authc.AuthenticationToken)
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		// TODO Auto-generated method stub
        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
        SysUser user = null;
		try {
			user = sysUserDao.findSingleByName(token.getUsername());
		} catch (DataAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchElementException e) {
			
			logger.debug("Could not find data , " +  e.getLocalizedMessage() );
			
			throw new UnknownAccountException("Account doest not exist in system! ");
		
		
		}
        
        // --- use another setting ----

        return  handlePolicy(user);
	}

}
